#include "BezierSurface.h"

/********************************************************************************************************
Constructor & Destructor
********************************************************************************************************/

//Default Constructor
BezierSurface::BezierSurface(){

}

BezierSurface::BezierSurface(float* vertexControl, int nbControlPointsI, int nbControlPointsJ){

	_vertexControl = vertexControl;
	_nbControlPoints = nbControlPointsI * nbControlPointsJ;
	_nbControlPointsI = nbControlPointsI;
	_nbControlPointsJ = nbControlPointsJ;	

	computeVertex();

	_cubeControl = new Cube*[3];

	//Create cubes for control points
	for(int i = 0; i < _nbControlPoints; ++i)
	{
		
		float posCube[3];
		for(int j = 0; j < 3; ++j)
		{
			posCube[j] = _vertexControl[i * 3 + j];
		}
		
		Cube* cube = new Cube(posCube, 0.1f);
		_cubeControl[i] = cube;
	}


	//Set Color on all vertex	
	m_red = new float[m_nbVertex * 3];

	for(int i = 0; i < m_nbVertex * 3; i++){
		m_red[i++] = 0.0f;
		m_red[i++] = 1.0f;
		m_red[i] = 0.0f;
	}
	
	_colorControlPoints = new float[_nbControlPoints * 3];

	for(int i = 0; i < _nbControlPoints * 3; i++){
		_colorControlPoints[i++] = 0.0f;
		_colorControlPoints[i++] = 0.0f;
		_colorControlPoints[i] = 1.0f;
	}

}


BezierSurface::~BezierSurface(){
	delete[] _vertexControl;
	delete[] _colorControlPoints;
	delete[] _cubeControl;
}



/********************************************************************************************************
Compute
********************************************************************************************************/

void BezierSurface::computeVertex()
{
	float u = 0;
	float v = 0;

	float stepU = 0.1f;
	float stepV = 0.1f;

	std::vector<float> tempVertex = std::vector<float>();

	int nbPoints = 0;
	int nbPointByLine = 0;
	while(u < 1)
	{	
		v = 0;
		nbPointByLine = 0;
		while(v < 1)
		{
			float* newPoint = bezierSurfaceValue(_vertexControl, _nbControlPointsI, _nbControlPointsJ, u, v);
			for(int i = 0; i < 3; ++i)
				tempVertex.push_back(newPoint[i]);

			nbPoints++;
			nbPointByLine++;
			v += stepV;
		}
		u += stepU;
	}

	m_vertex = new float[nbPoints * 3];
	m_nbVertex = nbPoints;

	for(unsigned int i = 0; i < tempVertex.size(); ++i)
	{
		m_vertex[i] = tempVertex[i];
	}
		
	//Compute Faces index
	std::vector<int> indexFaces = std::vector<int>();

	for(int i = 0; i + nbPointByLine < m_nbVertex -1; i++){
		if ((i +1) % nbPointByLine != 0)
		{
			//First Face
			indexFaces.push_back(i);
			indexFaces.push_back(i + 1);
			indexFaces.push_back(i + nbPointByLine + 1);

			
			//Second Face
			indexFaces.push_back(i);
			indexFaces.push_back(i + nbPointByLine + 1);
			indexFaces.push_back(i + nbPointByLine);			
			
		}

	}

	m_index = new unsigned int[indexFaces.size()];
	int numIndex = 0;
	int nb = 0;

	for(unsigned int i = 0; i < indexFaces.size(); i++){
		m_index[i] = indexFaces[i];			 
	}
	m_nbIndex = indexFaces.size();
	
	
}

float* BezierSurface::bezierSurfaceValue(float* points, int nbPoints, int nbPointsJ, float u, float v)
{
	float* newPoint = new float[3];
	newPoint[0] = 0.0f;
	newPoint[1] = 0.0f;
	newPoint[2] = 0.0f;


	for(int i = 0; i < nbPoints; ++i)
	{
		float tempX = 0;
		float tempY = 0;
		float tempZ = 0;

		float bernsteinI = Math::bernsteinPolynomial(nbPoints, u, i);
		/*
		newPoint[0] += bernsteinI;// * points[i];
		newPoint[1] += bernsteinI;// * points[i +1];
		newPoint[2] += bernsteinI;// * points[i + 2];
		*/
		for(int j = 0; j < nbPointsJ; ++j)
		{
			float bernsteinJ = Math::bernsteinPolynomial(nbPointsJ, v, j);
			tempX += bernsteinJ * points[i * 3 * nbPointsJ + j * 3];
			tempY += bernsteinJ * points[i * 3 * nbPointsJ + j * 3 + 1];
			tempZ += bernsteinJ * points[i * 3 * nbPointsJ + j * 3 + 2];
		}
		newPoint[0] += tempX * bernsteinI;
		newPoint[1] += tempY * bernsteinI;
		newPoint[2] += tempZ * bernsteinI;

	}



	return newPoint;
}


/********************************************************************************************************
Draw
********************************************************************************************************/

//Draw the object
void BezierSurface::draw(Matrice &modelview, Matrice &projection)
{

	Object3D::draw(modelview, projection);

	drawControlPoints(modelview, projection);
	//drawVertex(modelview, projection);
}


//Draw Vertex of Object
void BezierSurface::drawVertex(Matrice &modelview, Matrice &projection)
{
	
	drawControlPoints(modelview, projection);

	Object3D::drawVertex(modelview, projection);
}

//Draw Control Points of Object
void BezierSurface::drawControlPoints(Matrice &modelview, Matrice &projection)
{
	for(int i = 0; i < _nbControlPoints; ++i)
	{
		glLoadName(i);
		_cubeControl[i]->draw(modelview, projection);
	}
		

	/*
	modelview.push();

	//Shader & Vertex Init
	glUseProgram(m_shaderColor.getProgramID());
	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);

	//Shader Values
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, _vertexControl);
	glUniformMatrix4fv(glGetUniformLocation(m_shaderColor.getProgramID(), "projection"), 1, GL_TRUE, projection.getValues());
	glUniformMatrix4fv(glGetUniformLocation(m_shaderColor.getProgramID(), "modelview"), 1, GL_TRUE, modelview.getValues());

	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,0, _colorControlPoints);

	//Draw Vertex
	glBegin(GL_POINTS);

	for(int i = 0; i < _nbControlPoints; i++){
		glVertex3f(_vertexControl[(i * 3)], _vertexControl[(i * 3)+1], _vertexControl[(i * 3)+2]);
	}
	glEnd();

	//Disable shader and vertex		
	glDisableVertexAttribArray(1);
	glDisableVertexAttribArray(0);
	glUseProgram(0);

	modelview.pop();
	*/
}
